#include "resultsDialogAction.h"

//Create the dialog that will show the results of the executions
resultsDialogAction::resultsDialogAction(viewer* v)
: resultsDialog("Results of the executions", *v, false, false),
buttonAlignment(Gtk::ALIGN_RIGHT, Gtk::ALIGN_BOTTOM, 0.11, 0.0)
{
	executions = 0;
	resultsDialog.resize(600,400);

	//Get the default VBox of the dialog and add to it our vertical box
	Gtk::VBox * box = resultsDialog.get_vbox();
	box->pack_start(infoBox);

	//Pack the elements of the dialog (the tree and a button) in the infobox
	infoBox.pack_start(scrollInfo, Gtk::PACK_EXPAND_WIDGET);
	infoBox.pack_start(buttonAlignment, Gtk::PACK_SHRINK);
	buttonAlignment.add(button);

	//Create a button to clear the tree
	button.set_label("Clear");
	button.set_border_width(4);

	//When the CLEAR button is clicked, the function on_clear_tree_clicked is called
	button.signal_clicked().connect(sigc::mem_fun(*this, &resultsDialogAction::on_clear_tree_clicked));

	//Add the scrolled window
	scrollInfo.add(tree);
	scrollInfo.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);

	//Move it to the right top corner
	resultsDialog.set_position(Gtk::WIN_POS_NONE);
	Glib::RefPtr<Gdk::Screen> screen = Gdk::Screen::get_default();
	int resX = screen->get_width();
	infoBox.set_size_request(200,150);
	resultsDialog.move(resX-600, 0);

	//Add the TreeView’s view columns:
	tree.append_column("Executions", infoT.field);
	tree.append_column("Results", infoT.value);

	//Create a tiny menu popup for the new row to be able to delete it
	Glib::RefPtr<Gtk::ActionGroup> agRow = Gtk::ActionGroup::create();
	agRow->add(Gtk::Action::create("RemoveMenu", "Remove Menu"));
	agRow->add(Gtk::Action::create("Remove", "Remove"), sigc::mem_fun(this, &resultsDialogAction::on_remove_row));

	rowManager = Gtk::UIManager::create();
	rowManager->insert_action_group(agRow);
	v->add_accel_group(rowManager->get_accel_group());

	//Layout of this menu
	Glib::ustring info =
		   "<ui>"
		   " <popup name='RemoveMenu'>"
		   "    <menuitem action='Remove'/>"
		   " </popup>"
		   "</ui>";

	#ifdef GLIBMM_EXCEPTIONS_ENABLED
	try
	{
	   rowManager->add_ui_from_string(info);
	}
	catch(const Glib::Error& ex)
	{
		Gtk::MessageDialog dialog(*v, "Building menus failed.", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, false);
		dialog.set_secondary_text(ex.what());
		dialog.show();
	}
	#else
	std::auto_ptr<Glib::Error> ex;
	rowManager->add_ui_from_string(info, ex);
	if(ex.get())
	{
		Gtk::MessageDialog dialog(*v, "Building menus failed.", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, false);
		dialog.set_secondary_text(ex.what());
		dialog.show();
	}
	#endif //GLIBMM_EXCEPTIONS_ENABLED

	//Get the popup menu
	Gtk::Menu* popupMenu = dynamic_cast<Gtk::Menu*>(rowManager->get_widget("/RemoveMenu"));
	if(!popupMenu)
	{
		Gtk::MessageDialog dialog(*v, "Menu not found.", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, false);
		dialog.show();
	}

	//Detect a button press event in the row
	tree.set_events(Gdk::BUTTON_PRESS_MASK);
	tree.signal_event().connect(sigc::mem_fun(*this, &resultsDialogAction::on_row_pressed));

	//Create the new tree
	refTree = Gtk::TreeStore::create(infoT);
	tree.set_model(refTree);

	//Show the content of the dialog
	box->show_all_children();
}


//Show the results dialog
void resultsDialogAction::showResultsDialog()
{
	resultsDialog.show();
}


//Add a row in the tree with the information of the solution passed as argument
void resultsDialogAction::addRow(results* res, int size)
{
	//Fill the TreeView’s model with the solution data of this execution
	Gtk::TreeModel::iterator it = refTree->get_iter(Gtk::TreePath("0"));
	Gtk::TreeModel::Row row;
	if(!it) row = *(refTree->append());
	else row = *(refTree->insert(it));
	std::stringstream o;
	o << ++executions;
	std::string s;
	switch(executions)
	{
		case 1:
			s = o.str() + "st execution";
			break;
		case 2:
			s = o.str() + "nd execution";
			break;
		case 3:
			s = o.str() + "rd execution";
			break;
		default:
			s = o.str() + "th execution";
	}
	row[infoT.field] = s;
	row[infoT.value] = "";

	//Algorithm used
	Gtk::TreeModel::Row childrow = *(refTree->append(row.children()));
	childrow[infoT.field] = "Algorithm";
	childrow[infoT.value] = res->getAlgorithm();

	//Data structure used
	childrow = *(refTree->append(row.children()));
	childrow[infoT.field] = "Data structure";
	childrow[infoT.value] = res->getDataStructure();

	//Cost of the solution found
	childrow = *(refTree->append(row.children()));
	childrow[infoT.field] = "Cost";
	std::stringstream out2;
	if(res->getCost())	out2 << res->getCost();
	else out2 << "There was no possible path";
	childrow[infoT.value] = out2.str();

	//Visited cells during the execution
	childrow = *(refTree->append(row.children()));
	childrow[infoT.field] = "Visited cells";
	std::stringstream out3;
	out3 << res->getVisitedNodes();
	std::stringstream out4;
	out4 << size;
	childrow[infoT.value] = out3.str() + "/" + out4.str();

	//Execution time of the algorithm
	childrow = *(refTree->append(row.children()));
	childrow[infoT.field] = "Execution time";
	char buf[15];
	sprintf(buf, "%.5f", res->getExecutionTime() * 1000);
	strcat(buf, " ms");
	childrow[infoT.value] = buf;

	//Execution time of the add member
	childrow = *(refTree->append(row.children()));
	childrow[infoT.field] = "Add node";
	std::stringstream out5;
	out5 << res->getAdd().first;
	out5 << " calls / Average execution time: ";
	char buf2[15];
	sprintf(buf2, "%.5f", res->getAdd().second);
	strcat(buf2, " ms");
	childrow[infoT.value] = out5.str() + buf2;

	//Execution time of the remove member
	childrow = *(refTree->append(row.children()));
	childrow[infoT.field] = "Modify node";
	std::stringstream out6;
	out6 << res->getModify().first;
	out6 << " calls / Average execution time: ";
	char buf3[15];
	sprintf(buf3, "%.5f", res->getModify().second);
	strcat(buf3, " ms");
	childrow[infoT.value] = out6.str() + buf3;

	//Execution time of the select lowest member
	childrow = *(refTree->append(row.children()));
	childrow[infoT.field] = "Select node with lowest cost";
	std::stringstream out7;
	out7 << res->getSelectLowest().first;
	out7 << " calls / Average execution time: ";
	char buf4[15];
	sprintf(buf4, "%.5f", res->getSelectLowest().second);
	strcat(buf4, " ms");
	childrow[infoT.value] = out7.str() + buf4;

	//Execution time of the find member
	childrow = *(refTree->append(row.children()));
	//Gtk::TreeModel::iterator it = &childrow;
	childrow[infoT.field] = "Find node";
	std::stringstream out8;
	out8 << res->getFind().first;
	out8 << " calls / Average execution time: ";
	char buf5[15];
	sprintf(buf5, "%.5f", res->getFind().second);
	strcat(buf5, " ms");
	childrow[infoT.value] = out8.str() + buf5;

	//Expand the row that has been just created and scroll to it
	tree.expand_row (Gtk::TreePath("0"), true);
	tree.set_cursor(Gtk::TreePath("0"));
	tree.scroll_to_row(Gtk::TreePath("0"));

	//Show the dialog in case it was not active
	resultsDialog.show();
}


//It shows the popup menu for the row clicked with the right button of the mouse
bool resultsDialogAction::on_row_pressed(GdkEvent* e)
{
	if( (e->type == GDK_BUTTON_PRESS))
	{
		GdkEventButton* event = (GdkEventButton*)e;
		if(event->button == 3)
		{
			//Obtain the path to the row clicked
			Gtk::TreePath path; 
			tree.get_path_at_pos(int(event->x), int(event->y),path);

			//Obtain the popupMenu		
			Gtk::Menu* popupMenu = dynamic_cast<Gtk::Menu*>(rowManager->get_widget("/RemoveMenu"));

			//If the menu has been previously created and the row selected is a parent
			if(popupMenu && path.to_string().find(":") == std::string::npos)
			{
				//Popup the menu
				popupMenu->popup(event->button, event->time);
			
				//Store the iterator that points to this row
				iter = refTree->get_iter(path);

				return true;
			}
		}
	}
	return false;
}


//Signal handler activated when the clear button is clicked
//It clears the tree
void resultsDialogAction::on_clear_tree_clicked()
{
	refTree->clear();
}


//Remove the row pointed by iter from the tree model
void resultsDialogAction::on_remove_row()
{
	refTree->erase(iter);
}